using System;
using System.Diagnostics;
using System.Security.Principal;

namespace KodeIT.Web
{
    internal static class EventHelper
    {
        private static string ExceptionToString(Exception exp)
        {
            return String.Format(
                "Exception information:\r\n" +
                "    Type: {0}\r\n" +
                "    Message: {1}", exp.GetType().ToString(), exp.Message);
        }

        private static string ContextToString(FilterEvent filterEvent, Type instanceType)
        {
            return String.Format(
                "Context instance information:\r\n" +
                "    Notification: {0}\r\n" +
                "    Instance: {1}",
                Enum.GetName(filterEvent.GetType(), filterEvent),
                instanceType.AssemblyQualifiedName);
        }

        private static string TypeToString(Type factoryType, string type)
        {
            return String.Format(
                "Context {0} information:\r\n" +
                "    Instance: {1}",
                type,
                factoryType.AssemblyQualifiedName);
        }

        private static string EventToString(FilterEvent filterEvent)
        {
            return String.Format(
                "Event information:\r\n" +
                "    Notification: {0}",
                Enum.GetName(filterEvent.GetType(), filterEvent));
        }

        private static string ProcessToString()
        {
            Process process = Process.GetCurrentProcess();
            return String.Format(
                "Process information:\r\n" +
                "    Process ID: {0}\r\n" +
                "    Process name: {1}.exe\r\n" +
                "    Account name: {2}",
                process.Id,
                process.ProcessName,
                WindowsIdentity.GetCurrent().Name);
        }

        private static void Write(string text, EventLogEntryType type)
        {
            try
            {
                using (ImpersonationContext imp = new ImpersonationContext())
                {
                    using (EventLog evt = new EventLog("Application"))
                    {
                        evt.Source = "Filter.NET Framework";
                        evt.WriteEntry(text, type);
                    }
                }
            }
            catch (Exception exp)
            {
                Trace.WriteLine("Unable to write to the event log\r\n\r\n" + exp);
            }
        }

        internal static void WriteInstance(FilterEvent filterEvent, Type instanceType, Exception exp)
        {
            string eventText = String.Format("Unhandled exception while processing filter notification\r\n\r\n" +
                "{0}\r\n\r\n" +
                "{1}\r\n\r\n" +
                "{2}\r\n\r\n" +
                "Stack trace:\r\n{3}",
                ContextToString(filterEvent, instanceType),
                ProcessToString(),
                ExceptionToString(exp),
                exp.StackTrace);

            Write(eventText, EventLogEntryType.Error);
        }

        internal static void WriteEvent(FilterEvent filterEvent, Exception exp)
        {
            string eventText = String.Format("Unhandled exception while updating filter event\r\n\r\n" +
                "{0}\r\n\r\n" +
                "{1}\r\n\r\n" +
                "{2}\r\n\r\n" +
                "Stack trace:\r\n{3}",
                EventToString(filterEvent),
                ProcessToString(),
                ExceptionToString(exp),
                exp.StackTrace);

            Write(eventText, EventLogEntryType.Error);
        }

        internal static void Write(string text, Exception exp)
        {
            string eventText = String.Format("{0}\r\n\r\n" +
                "{1}\r\n\r\n" +
                "{2}\r\n\r\n" +
                "Stack trace:\r\n{3}",
                text,
                ProcessToString(),
                ExceptionToString(exp),
                exp.StackTrace);

            Write(eventText, EventLogEntryType.Error);
        }

        internal static void WriteFactory(string text, Type factoryType, Exception exp)
        {
            Write(text, factoryType, exp, "factory");
        }

        internal static void WriteInstance(string text, Type instanceType, Exception exp)
        {
            Write(text, instanceType, exp, "instance");
        }

        // {0} = text
        // {1} = TypeToString(factoryType, type)
        // {2} = ProcessToString()
        // {3} = ExceptionToString(exp)
        // {4} = exp.StackTrace
        // {5} = Filter.Net Version
        // {6} = .Net Version
        // {7} = type "ContextFactory Error"

        private static void Write(string text, Type factoryType, Exception exp, string type)
        {
            string eventText = String.Format("{0}\r\n\r\n" +
                "{1}\r\n\r\n" +
                "{2}\r\n\r\n" +
                "{3}\r\n\r\n" +
                "Stack trace:\r\n{4}",
                text,
                TypeToString(factoryType, type),
                ProcessToString(),
                ExceptionToString(exp),
                exp.StackTrace);

            Write(eventText, EventLogEntryType.Error);
        }
    }
}
